package cn.virens.common.util.components.pool;


import cn.virens.common.util.core.Assert;

import java.io.Serializable;

@SuppressWarnings("serial")
public class VirObjectWarp<K, V> implements AutoCloseable, Serializable {
    private final VirObjectPool<K, V> pool;

    private final V value;
    private final K key;

    private VirObjectWarp(VirObjectPool<K, V> pool, K key, V value) {
        this.value = Assert.isNull(value);
        this.pool = Assert.isNull(pool);
        this.key = Assert.isNull(key);
    }

    public final K key() {
        return key;
    }

    public final V value() {
        return value;
    }

    @Override
    public void close() throws Exception {
        if (key != null && pool.getNumActive(key) > 0) {
            this.pool.returnObject(key, value);
        }
    }

    /**
     * 根据KEY 获取对应的包装对象
     *
     * @param <K>  K类型
     * @param <V>  V类型
     * @param pool 对象池
     * @param key  KEY值
     * @return 包装对象
     * @throws Exception
     */
    public static <K, V> VirObjectWarp<K, V> key(VirObjectPool<K, V> pool, K key) throws Exception {
        return new VirObjectWarp<>(pool, key, pool.borrowObject(key));
    }

    /**
     * 根据KEY 获取对应的包装对象
     *
     * @param <K>                 K类型
     * @param <V>                 V类型
     * @param pool                对象池
     * @param key                 KEY值
     * @param borrowMaxWaitMillis 超时时间
     * @return 包装对象
     * @throws Exception
     */
    public static <K, V> VirObjectWarp<K, V> key(VirObjectPool<K, V> pool, K key, long borrowMaxWaitMillis) throws Exception {
        return new VirObjectWarp<>(pool, key, pool.borrowObject(key, borrowMaxWaitMillis));
    }

    /**
     * 根据别名获取对应的包装对象
     *
     * @param <K>   K类型
     * @param <V>   V类型
     * @param pool  对象池
     * @param alias 别名值
     * @return 包装对象
     * @throws Exception
     */
    public static <K, V> VirObjectWarp<K, V> alias(VirObjectPool<K, V> pool, String alias) throws Exception {
        return key(pool, Assert.isNull(pool.getKeyWithAlias(alias), "当前别名未绑定对象"));
    }

    /**
     * 根据别名获取对应的包装对象
     *
     * @param <K>                 K类型
     * @param <V>                 V类型
     * @param pool                对象池
     * @param alias               别名值
     * @param borrowMaxWaitMillis 超时时间
     * @return 包装对象
     * @throws Exception
     */
    public static <K, V> VirObjectWarp<K, V> alias(VirObjectPool<K, V> pool, String alias, long borrowMaxWaitMillis) throws Exception {
        return key(pool, Assert.isNull(pool.getKeyWithAlias(alias), "当前别名未绑定对象"), borrowMaxWaitMillis);
    }
}
